package by.epam.xslttask.command;

import by.epam.xslttask.constants.ProductConstants;
import by.epam.xslttask.dto.Product;
import by.epam.xslttask.logger.LoggerType;
import by.epam.xslttask.logger.XSLTLogger;
import by.epam.xslttask.managers.LogManager;
import by.epam.xslttask.managers.PathManager;
import javax.servlet.ServletException;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by IntelliJ IDEA.
 * User: Darya_Hrishanovich
 * Date: 7/19/12
 * Time: 8:09 AM
 * To change this template use File | Settings | File Templates.
 */
public final class SaveCommand extends Command {
    private static final String NOT_FORM = "notForm";
    private static final String EDIT_XML = "editXml";
    private static final String GOODSLIST = "goodsList";
    private static final String ERROR = "error";
    private static final String COMMAND = "command";
    private static final String TYPE = "type";
    private static final String SHOW = "show";
    private String xml;
    private Product product;
    private Map<String, String> params;
    private Templates editTemplates;

    public SaveCommand(String relPath, Product product) {
        super(relPath);
        this.product = product;
    }

    private void setParameters(Transformer t, Product product) {
        t.setParameter(NOT_FORM, "1");
        t.setParameter(ProductConstants.CATEGORY, product.getCategory());
        t.setParameter(ProductConstants.SUBCATEGORY, product.getSubcategory());
        t.setParameter(ProductConstants.NAME, product.getName());
        t.setParameter(ProductConstants.PRODUCER, product.getProducer());
        t.setParameter(ProductConstants.MODEL, product.getModel());
        t.setParameter(ProductConstants.DATE, product.getDate());
        t.setParameter(ProductConstants.COLOR, product.getColor());
        t.setParameter(ProductConstants.NOT_IN_STOCK, product.isNotInStock());
        t.setParameter(ProductConstants.PRICE, product.getPrice());
        AtomicBoolean errorExists = new AtomicBoolean(false);
        t.setParameter(ERROR, errorExists);
    }
    
    private void transformXml(TransformerFactory tFactory) throws TransformerException, IOException {
        String xsl = getRelPath() + PathManager.getProperty(EDIT_XML);
        Source xslSource = new StreamSource(new File(xsl));
        Transformer t;
        if(editTemplates == null) {
            editTemplates = tFactory.newTemplates(xslSource);
        }
        t = editTemplates.newTransformer();
        setParameters(t, product);

        StringWriter sw = new StringWriter();
        t.transform(new StreamSource(xml), new StreamResult(sw));
        AtomicBoolean errorExists = (AtomicBoolean) t.getParameter(ERROR);
        String info = sw.toString();
        if(errorExists.get()) {             //error in validation
            PrintWriter pw = getOut();
            pw.write(info);
        }
        else {
            writeXml(info);
            params = new HashMap();
            params.put(COMMAND, SHOW);
            params.put(TYPE, GOODSLIST);
            params.put(ProductConstants.CATEGORY, product.getCategory());
            params.put(ProductConstants.SUBCATEGORY, product.getSubcategory());
        }
        sw.close();
    }

    @Override
    public Map<String, String> execute() throws IOException, ServletException {
        xml = PathManager.getProperty(PathManager.XML);

        try {
            TransformerFactory tFactory = TransformerFactory.newInstance();
            getLock().writeLock().lock();
            transformXml(tFactory);
            if(params != null) {
                return params;
            }
        } catch (TransformerException e) {
            String message = LogManager.getProperty(LogManager.TRANSFORM_ERROR);
            XSLTLogger.logMessage(message, SaveCommand.class, LoggerType.ERROR);
            throw new ServletException(e);
        }
        finally {
            getLock().writeLock().unlock();
        }
        return null;   // if we shouldn't pass parameters and redirect
    }

    private void writeXml(String xmlString) {       //write result string to xml file
        File file = new File(xml);
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter
                    (new OutputStreamWriter(new FileOutputStream(file)));
        } catch (FileNotFoundException e) {
            String message = LogManager.getProperty(LogManager.FILE_NOT_FOUND);
            XSLTLogger.logMessage(message, SaveCommand.class, LoggerType.ERROR);
        }
        if (bw != null) {
            try {
                bw.write(xmlString);
                bw.flush();
            } catch (IOException e) {
                String message = LogManager.getProperty(LogManager.IO_EXCEPTION);
                XSLTLogger.logMessage(message, SaveCommand.class, LoggerType.ERROR);
            }
            finally {
                try {
                    bw.close();
                } catch (IOException e) {
                    String message = LogManager.getProperty(LogManager.IO_EXCEPTION);
                    XSLTLogger.logMessage(message, SaveCommand.class, LoggerType.ERROR);
                }
            }
        }
    }
}
